import 'dart:math';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_utils/flutter_utils.dart';

///文字后面带图标且不会随着文字裁剪而消失 需要传入文字的最大宽度
class TextSpanIcon extends StatefulWidget {
  const TextSpanIcon(
      this.text, {
        Key? key,
        this.textTap,
        this.style,
        this.textDirection,
        this.textAlign,
        this.textScaleFactor,
        this.maxLines = 2,
        this.semanticsLabel,
        this.iconText,
        required this.textMaxWidth,
      }) : assert(maxLines > 0),
        super(key: key);

  final String text;
  final GestureTapCallback? textTap;
  final TextStyle? style;
  final TextDirection? textDirection;
  final TextAlign? textAlign;
  final double? textScaleFactor;
  final int maxLines;
  final String? semanticsLabel;
  final Widget? iconText;
  final double textMaxWidth;

  @override
  TextSpanIconState createState() => TextSpanIconState();
}

class TextSpanIconState extends State<TextSpanIcon> {
  TapGestureRecognizer? _textTapGestureRecognizer;
  late String _text;

  @override
  void initState() {
    super.initState();
    _text = TextUtil.displayEmojiText(widget.text);
    _textTapGestureRecognizer = TapGestureRecognizer()
      ..onTap = _textTapped;
  }

  @override
  void dispose() {
    _textTapGestureRecognizer!.dispose();
    super.dispose();
  }

  void _textTapped() {
    widget.textTap?.call();
  }

  @override
  Widget build(BuildContext context) {
    final DefaultTextStyle defaultTextStyle = DefaultTextStyle.of(context);
    TextStyle? effectiveTextStyle = widget.style;
    if (widget.style == null || widget.style!.inherit) {
      effectiveTextStyle = defaultTextStyle.style.merge(widget.style);
    }

    final iconText = widget.iconText ?? Container();

    final link = TextSpan(
      text: '\u2026 ',
      style: effectiveTextStyle,
    );

    final icon = TextSpan(
      text: '',
      children: [
        WidgetSpan(
          child: iconText
        )
      ]
    );

    final text = TextSpan(
        text: '${_text}我',
        style: effectiveTextStyle,
    );

    Widget result = LayoutBuilder(
      builder: (BuildContext context, BoxConstraints constraints) {
        assert(constraints.hasBoundedWidth);
       final double maxWidth = constraints.maxWidth;

        final textAlign = widget.textAlign ?? defaultTextStyle.textAlign ?? TextAlign.start;
        final textDirection = widget.textDirection ?? Directionality.of(context);
        final textScaleFactor = widget.textScaleFactor ?? MediaQuery.textScaleFactorOf(context);
        final locale = Localizations.localeOf(context);

        TextPainter textPainter = TextPainter(
          text: link,
          textAlign: textAlign,
          textDirection: textDirection,
          textScaleFactor: textScaleFactor,
          maxLines: widget.maxLines,
          locale: locale,
        );
        textPainter.layout(minWidth: constraints.minWidth, maxWidth: widget.textMaxWidth);
        final linkSize = textPainter.size;

        textPainter.text = text;
        textPainter.layout(minWidth: constraints.minWidth, maxWidth: widget.textMaxWidth);
        final textSize = textPainter.size;

        TextSpan textSpan;
        if (textPainter.didExceedMaxLines) {
          var position = textPainter.getPositionForOffset(Offset(
            textSize.width - linkSize.width,
            textSize.height,
          ));
          final endOffset = textPainter.getOffsetBefore(position.offset)!;

          textSpan = TextSpan(
            style: effectiveTextStyle,
            children: <TextSpan>[
              TextSpan(
                text: _text.substring(0, max(endOffset, 0)),
                recognizer: _textTapGestureRecognizer
              ),
              link,
              icon,
            ],
          );
        } else {
          textSpan = TextSpan(
            style: effectiveTextStyle,
            children: <TextSpan>[
              TextSpan(
                text: _text,
                recognizer: _textTapGestureRecognizer
              ),
              icon
            ],
          );
        }

        return RichText(
          text: textSpan,
          softWrap: true,
          textDirection: textDirection,
          textAlign: textAlign,
          textScaleFactor: textScaleFactor,
          overflow: TextOverflow.clip,
        );
      },
    );

    return result;
  }
}
